package com.lancoo.edu.platform.operation.commons.utils.database;

import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;

/**
 * @author zhang.ws
 * @date 2024/1/29 11:14
 * @description mysql导出导入工具类
 */
@Slf4j
public class MysqlExportImportUtil {

    private final static String FORMAT_DATE_TIME_STR = "yyyyMMddHHmm";

    /**
     * 组装数据库备份导出命令
     *
     * @return 数据库备份导出命令
     */
    private static String getExportCommand(String mysqlDumpPath, String userName,
                                           String password, String host,
                                           String port, String dbNames) {
        String[] dbNameArray = dbNames.split(",");
        if (dbNameArray.length == 1) {
            return mysqlDumpPath + "mysqldump" +
                    " -h" +
                    host +
                    " -P" +
                    port +
                    " -u" +
                    userName +
                    " -p" +
                    password +
                    " --skip-extended-insert" +
                    " --databases " +
                    dbNameArray[0];
        } else {
            StringBuilder command = new StringBuilder(mysqlDumpPath + "mysqldump" +
                    " -h" +
                    host +
                    " -P" +
                    port +
                    " -u" +
                    userName +
                    " -p" +
                    password +
                    " --skip-extended-insert" +
                    " --databases ");
            for (String dbName : dbNameArray) {
                command.append(dbName).append(" ");
            }
            return command.toString();
        }
    }

    /**
     * 组装数据库备份导入命令
     *
     * @return 数据库备份导入命令
     */
    private static String getImportCommand(String mysqlDumpPath, String userName,
                                           String password, String host,
                                           String port, String dbName) {
        return mysqlDumpPath + "mysql" +
                " -h" +
                host +
                " -P" +
                port +
                " -u" +
                userName +
                " -p" +
                password;
    }

    /**
     * 组装数据库备份导入命令
     *
     * @return 数据库备份导入命令
     */
    private static String[] getImportCommandArray(String mysqlDumpPath, String userName,
                                                  String password, String host,
                                                  String port, String dbName, String filePath) {
        return new String[]{
                mysqlDumpPath + "mysql" +
                        " -h" + host +
                        " -P" + port +
                        " -u" + userName +
                        " -p" + password +
                        " " + dbName,
                " source " + filePath,
        };
    }


    /**
     * 导出
     *
     * @param mysqlDumpPath mysql的Dump命令地址
     * @param userName      登录mysql数据库用户名
     * @param password      登录mysql数据库密码
     * @param host          mysql数据库IP
     * @param port          mysql数据库端口
     * @param dbName        要导出的数据库
     * @param fileDir       要导出数据文件所在目录
     * @param fileName      导出文件名称
     * @return 是否成功 true/false
     */
    public static String exportSql(String mysqlDumpPath, String userName, String password, String host, String port, String dbName, String fileDir, String fileName) {
        String command = getExportCommand(mysqlDumpPath, userName, password, host, port, dbName);
        log.info("【数据库备份命令：{}】", command);
        log.info("【数据库导出文件地址：{}{}】", fileDir, fileName);
        File dir = new File(fileDir);
        if (!dir.exists()) {
            if (!dir.mkdirs()) {
                throw new RuntimeException("文件夹创建失败");
            }
        }
        Path path = Paths.get(fileDir + fileName);
        try (PrintWriter printWriter = new PrintWriter(new OutputStreamWriter(Files.newOutputStream(path), StandardCharsets.UTF_8))) {
            Process exec = Runtime.getRuntime().exec(command);
            try (InputStreamReader inputStreamReader = new InputStreamReader(exec.getInputStream(), StandardCharsets.UTF_8);
                 BufferedReader bufferedReader = new BufferedReader(inputStreamReader)) {
                 String line;
                 while ((line = bufferedReader.readLine()) != null) {
                    printWriter.println(line);
                 }
                 printWriter.flush();
                 if (exec.waitFor() == 0) {
                     log.info("【导出成功】");
                     return fileDir + fileName;
                 }
            }
        } catch (Exception e) {
            log.error("【数据库备份失败, errorMsg: {}】", e.getMessage(), e);
            try {
                Files.deleteIfExists(path);
            } catch (Exception exception) {
                log.error("【删除文件失败fileName: {}, errorMsg: {}】", path, exception.getMessage(), exception);
            }
        } finally {
            log.info("【清除资源缓存】");
        }
        return null;
    }

    /**
     * 导入
     *
     * @param mysqlDumpPath mysql的Dump命令地址
     * @param userName      登录mysql数据库用户名
     * @param password      登录mysql数据库密码
     * @param host          mysql数据库IP
     * @param port          mysql数据库端口
     * @param dbName        要导入的数据库
     * @param filePath      导入文件地址
     * @return 是否成功 true/false
     */
    public static boolean importSql(String mysqlDumpPath, String userName, String password, String host, String port, String dbName, String filePath) {
        String importCommand = getImportCommand(mysqlDumpPath, userName, password, host, port, dbName);
        log.info("【数据库导入命令：{}】", importCommand);
        log.info("【数据库导入地址文件：{}】", filePath);
        // 从文件中读取输入内容
        File inputFile = new File(filePath);
        try (BufferedReader reader = new BufferedReader(new FileReader(inputFile))) {
            Process exec = Runtime.getRuntime().exec(importCommand);
            try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(exec.getOutputStream()))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    writer.write(line);
                    writer.newLine();
                }
                writer.flush();
            }
            if (exec.waitFor() == 0) {
                log.info("【导入成功】");
                return true;
            }
        } catch (Exception e) {
            log.info("【导入失败】", e);
        }
        log.error("【导入失败】");
        return false;
    }

    /**
     * 导入
     *
     * @param mysqlDumpPath mysql的Dump命令地址
     * @param userName      登录mysql数据库用户名
     * @param password      登录mysql数据库密码
     * @param host          mysql数据库IP
     * @param port          mysql数据库端口
     * @param dbName        要导入的数据库
     * @param fileDir       导入文件夹
     * @return 是否成功 true/false
     */
    public static boolean importSqlV2(String mysqlDumpPath, String userName, String password, String host, String port, String dbName, String fileDir) {
        String[] importCommandArray = getImportCommandArray(mysqlDumpPath, userName, password, host, port, dbName, fileDir);
        log.info("【数据库导入命令：{}】", Arrays.toString(importCommandArray));
        log.info("【数据库导入地址文件夹：{}】", fileDir);
        try {
            Process process = Runtime.getRuntime().exec(importCommandArray[0]);
            //执行了第一条命令以后已经登录到mysql了，所以之后就是利用mysql的命令窗口
            //进程执行后面的代码
            try (OutputStreamWriter writer = new OutputStreamWriter(process.getOutputStream())) {
                // 导入命令
                writer.write(importCommandArray[1]);
                writer.flush();
            }
            if (process.waitFor() == 0) {
                log.info("【导入成功】");
                return true;
            }
        } catch (Exception e) {
            log.info("【导入失败】", e);
        }
        log.info("【导入失败】");
        return false;
    }
}
